from bson import ObjectId

from app.niuniu.cols import *
from app.niuniu.items import *


class Room:
    owner_key = 'room_owner'

    @staticmethod
    async def create(user_id: str):
        item = await room_col.find_one({'owner': user_id})
        if item:
            return item['_id']
        room_item = RoomItem(owner=user_id, players=[user_id])
        room_col.insert_one(room_item.dict())
        return room_item.id

    @staticmethod
    async def join(room_id: str, user_id: str) -> bool:
        item = await room_col.find_one({"_id": ObjectId(room_id)})
        if not item:
            return False
        await room_col.update_one({"_id": ObjectId(room_id)}, {"$push": {"players": user_id}})
        return True

    @staticmethod
    async def leave(room_id: str, user_id: str) -> bool:
        item = await room_col.find_one({"_id": ObjectId(room_id)})
        if not item:
            return False
        await room_col.update_one({"_id": ObjectId(room_id)}, {"$pull": {"players": user_id}})
        return True

    @staticmethod
    async def delete(room_id: str, user_id: str) -> None:
        item = await room_col.find_one({"_id": ObjectId(room_id)})
        if not item:
            return

        if item['owner'] == user_id:
            await room_col.delete_one({"_id": item['_id']})

    @staticmethod
    async def all_room():
        results = []
        cursor = await room_col.find()
        for room in cursor:
            results.append({"id": room['_id'], "owner": room['owner']})
        return results

    @staticmethod
    async def info(room_id: str):
        item = await room_col.find({"_id": ObjectId(room_id)})
        if item:
            return {"id": item['_id'], "owner": item['owner'], 'players': item['players']}


class Game:
    @staticmethod
    async def banker_data(user_id: str, room_id: str, round: int, poker: list[int]) -> None:
        if await games_col.find_one({'room_id': room_id, 'round': round, 'is_completed': True}):
            return

        game_item = GamesItem(room_id=room_id, round=round, banker_poker={user_id: poker})
        game_item.dict()
        await games_col.update_one(
            {'room_id': room_id, 'round': round, 'is_completed': False},
            {
                '$set': game_item.dict(exclude={'players_poker', 'created_at', 'id', 'point'}),
                '$setOnInsert': game_item.dict(include={'created_at'})
            },
            upsert=True
        )

    @staticmethod
    async def player_data(user_id: str, room_id: str, round: int, poker: list[int]) -> None:
        if await games_col.find_one({'room_id': room_id, 'round': round, 'is_completed': True}):
            return

        game_item = GamesItem(room_id=room_id, round=round)
        data = game_item.dict(exclude={'banker_poker', 'players_poker', 'created_at', 'id', 'point'})
        data[f'players_poker.{user_id}'] = poker
        await games_col.update_one(
            {'room_id': room_id, 'round': round, 'is_completed': False},
            {
                '$set': data,
                '$setOnInsert': game_item.dict(include={'created_at'})
            },
            upsert=True
        )

    @staticmethod
    async def game_completed(room_id: str, round: int) -> None:
        item = await games_col.find_one({'room_id': room_id, 'round': round, 'is_completed': False})
        if not item:
            return
        point = {}
        game_item = GamesItem(**item)
        for b_key, b_val in game_item.banker_poker.items():
            point[b_key] = 0
            for p_key, p_val in game_item.players_poker.items():
                b_nn = NiuNiu(b_val)
                p_nn = NiuNiu(p_val)
                print(b_nn, p_nn)
                if b_nn > p_nn:
                    point[b_key] += b_nn.rate
                    point[p_key] = b_nn.rate
                else:
                    point[b_key] -= p_nn.rate
                    point[p_key] = p_nn.rate
        await games_col.update_one(
            {'room_id': room_id, 'round': round},
            {"$set": {"is_completed": True, 'point': point}}
        )

    @staticmethod
    async def get_game(room_id: str, round: int):
        return await games_col.find_one({"room_id": room_id, "round": round})

    @staticmethod
    async def get_room_games(room_id: str):
        cursor = await games_col.find({"room_id": room_id})
        for item in cursor.sort("round", 1):
            yield item


class NiuNiu:
    def __init__(self, num_list):
        num_list.sort()
        self.num_list = num_list
        self.max = self.num_list[-1]
        self._result = self.calc()
        self._rate = self.calc_rate()

    @property
    def result(self):
        return self._result

    @property
    def rate(self):
        return self._rate

    def __str__(self):
        if self._result >= 40:
            t = f"五花牛"
        elif self._result == -1:
            t = f"没牛"
        elif self._result == 10:
            t = f"牛牛"
        else:
            t = f"牛{self._result}"

        return t

    def __gt__(self, other):
        if self._result == other._result:
            for i in range(4, -1, -1):
                if self.num_list[i] != other.num_list[i]:
                    return self.num_list[i] > other.num_list[i]
            return True
        return self._result > other._result

    def calc_rate(self):
        """计算倍率"""
        if self._result in [7, 8]:
            return 2
        elif self._result == 9:
            return 3
        elif self._result == 10:
            return 4
        elif self._result >= 40:
            return 5
        return 1

    def calc(self):
        def sum_card(*args):
            r = 0
            for poke_num in args:
                x = int(poke_num / 4)
                r += x + 1 if x < 9 else 10
            return r

        if self.num_list[0] >= 40:
            return self.num_list[0]
        for i in range(3):
            for j in range(i + 1, 4):
                for k in range(j + 1, 5):
                    item = (self.num_list[i], self.num_list[j], self.num_list[k])
                    diff = set(self.num_list).difference(item)
                    x_point = sum_card(*item)
                    y_point = sum_card(*diff)
                    if x_point % 10 == 0:
                        return y_point % 10 if y_point % 10 != 0 else 10
        return -1


if __name__ == '__main__':
    import asyncio


    async def run():
        # await Game.banker_data('caifuliang', '1', 1, [44, 2, 9, 18, 39])
        # await Game.player_data('lee', '1', 1, [42, 20, 15, 37, 29])
        # await Game.player_data('zhang', '1', 1,[28, 13, 24, 35, 11])
        # await Game.player_data('wang', '1', 1,[47, 3, 21, 4, 0])
        await Game.game_completed('1', 1)


    asyncio.run(run())
